#include<unistd.h>
#include<stdint.h>
#include<functional>
#include<vector>
#include<memory>
#include<unordered_map>

#include<iostream>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimeTask{

private:
    uint64_t _id;      // 能够被找到这个定时器任务！因为id可能会很多所以使用uint64_t
    uint32_t _timeout; // 定时任务的超时时间！——决定了什么是被执行！
    TaskFunc _task_cb; // 定时器对象要执行的任务！——放在析构函数里面的！
    ReleaseFunc _release;//删除TimerWheel中的map中的保存的定时器的信息！防止内存泄漏！
    bool _canceled;//false表示没有被取消，true表示取消！

public:
    TimeTask(uint64_t id, uint32_t delay, const TaskFunc &cb)
        : _id(id), _timeout(delay), _task_cb(cb),_canceled(false)
    {}

    ~TimeTask()
    {
        if (_canceled == false)//任务取消要放在内部！而不是放在时间轮！如果放在时间轮让其销毁！那就是提前执行任务！
        {
            _task_cb(); // 销毁的时候执行任务
        }
        _release();
    }

    void SetRelease(const ReleaseFunc& cb)//这个释放函数由外部进行设置！
    {
        _release = cb;
    }

    void CanCeled(uint64_t id) { _canceled = true; }//取消任务

    uint32_t DelayTime() { return _timeout; }
};

class TimeWheel
{
    using PtrTask = std::shared_ptr<TimeTask>;
    using WeakTask= std::weak_ptr<TimeTask>;
private:
    int _capacity;//表盘的最大数量！——就是最大延迟时间！
    std::vector<std::vector<PtrTask>>  _wheel;//二维数组
    int _tick;//走到哪里释放哪里的对象！——是时间轮的秒针！
    std::unordered_map<uint64_t,WeakTask> _timers;
    //当我们要二次添加同一个定时器任务对象的时候，我们首先要找它们共同的一个计数器！
    //但是我们又不能重新用shared_ptr保存一份，放在map里面用于查找！因为这样子会导致计数器+1
    //即使数组里面的share_ptr都释放掉了！但是因为map里面还有一份！
    //所以这就会让其一直无法释放！所以我们必须使用weak_ptr让其不参与计数！
    //然后我们使用这个weak_ptr去构造shared_ptr这样子就可以让后面构建的对象共享同一个计数！
private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it != _timers.end())
        {
            _timers.erase(id);
        }
    }
public:
    TimeWheel()
        : _capacity(60), _tick(0),_wheel(_capacity)
    {
    }


    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)//添加定时任务！
    {
        PtrTask pt(new TimeTask(id,delay,cb));
        pt->SetRelease(std::bind(&TimeWheel::RemoveTimer,this,id));
        //当定时任务对象被销毁的时候，要从map里面将信息移除！
        //因为RemoveTimer有一个隐藏参数this和Release本身要求无参！所以我们可以使用bind来解决这个问题！

        int pos = (_tick + delay) % _capacity; // 防止越界！
        _wheel[pos].push_back(pt);//找到的位置是一数组！要插入数组中！

        _timers[id] = WeakTask(pt);
        //将本次要添加的TimeTask对象放入
        //要放入的是Weakptr而不是shared_ptr!
    }
    void TimerRefresh(uint64_t id)//刷新定时任务！
    {
        //刷新的逻辑就是通过id来查找到那个weak_Ptr，然后通过weak_ptr来实例化一个新的shared_ptr然后添加进时间轮中！
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            return;//没找到,就直接结束！定时任务无法刷新！
        }
        //找到构建一个shared_ptr出来！ 
        PtrTask pt = it ->second.lock();//lock获取weak_ptr管理的对象的对应的shared_ptr
        int delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity; // 防止越界！
        _wheel[pos].push_back(pt);//找到的位置是一数组！要插入数组中！
        //指向当前秒针指向的位置加上延迟的位置！
    }

    void TimeCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
        {
            return;//没找到,就直接结束！定时任务无法刷新！
        }
        PtrTask pt = it ->second.lock();
        pt->CanCeled(id);
    }


    void  RunTimerTask()//这个函数是每秒钟执行一次！相当于秒针走一次！
    {
        _tick = (_tick+1) % _capacity;
        _wheel[_tick].clear();//清空指定位置的数组就会将数组保存的所有管理定时器对象的shared_ptr释放掉！
    }


};

// //测试应该做一个测试类！
// class test
// {
// public:
//     test()
//     {
//         std::cout << "test class init !" << std::endl;
//     }
//     ~test()
//     {

//         std::cout << "test class delete !" << std::endl;
//     }
// };

// void TestTime(test* t)
// {
//     delete t;
// }

// int main()
// {
//     TimeWheel timewheel;
//     test* t = new test();
//     test* t2 = new test();
//     test* t3 = new test();

//     timewheel.TimerAdd(1,20,std::bind(TestTime,t));
//     timewheel.TimerAdd(2,40,std::bind(TestTime,t2));
//     timewheel.TimerAdd(3,30,std::bind(TestTime,t3));


//     for(int i = 0;i<100;i++)
//     {
//         std::cout << i <<std::endl;
//         if(i == 5)
//         {
//             timewheel.TimeCancel(3);
//             std::cout << "取消成功！" <<std::endl;
//         }
//         if(i == 30)
//         {
//             timewheel.TimerRefresh(2);
//             std::cout << "刷新成功！" <<std::endl;
//         }
//         timewheel.RunTimerTask();
//     }

// }










